<!DOCTYPE html>
<html>
  <head>
    <title>Scatter</title>
    <link rel="stylesheet" href="/static/css/nCov.css"> 
    <script src="/static/js/color-strategies.js"></script>
    <script src="/static/js/d3.min.js"></script>
  </head>
  <body style="text-align: center">
    <svg width="1650" height="920" id="mainsvg" class="svgs" style="background-color: #333333;"></svg>
    <script>
        // get main SVG and its attributes & setting hyper-parameters; 
        const svg = d3.select('#mainsvg');
        const width = +svg.attr('width');
        const height = +svg.attr('height');
        const margin = {top: 100, right: 200, bottom: 100, left: 120};
        const innerWidth = width - margin.left - margin.right;
        const innerHeight = height - margin.top - margin.bottom;
        //const xValue = (datum) => {return dates.indexOf(datum['日期'])};
        //const yValue = (datum) => {return datum['确诊人数']};
        const xValue = d => {return Math.log(d['确诊人数'] +1)};
        // const xValue = d => Math.log(d['感染率']+1);
        const yValue = d => {return Math.log(d['diffuse_smooth'] * 1000 + 1)};
        // const yValue = d => {return d['diffuse_smooth']};
        // const yValue = d => {return Math.log(d['新增确诊']+1)};
        const rValue = d => {return Math.sqrt(d['感染率']+1) * 10};
        let xScale, yScale;
        let maxX, maxY;
        let dates; 
        let aduration = 1000;
        let metapop;
        let keyHint = '地区';

        let name_map = {"武汉": "Wuhan",
            "黄石": "Huangshi",
            "十堰": "Shiyan",
            "荆州": "Jingzhou",
            "宜昌": "Yichang",
            "襄阳": "Xiangyang",
            "鄂州": "Ezhou",
            "荆门": "Jingmen",
            "孝感": "Xiaogan",
            "黄冈": "Huanggang",
            "咸宁": "Xianning",
            "恩施州": "Enshi",
            "随州": "Suizhou",
            "仙桃": "Xiantao",
            "天门": "Tianmen",
            "潜江": "Qianjiang",
            "神农架": "Shennongjia"
        };

        var color = ["#c25ec3", //鄂州
                "#73A373", //恩施州
                "#52f3a9", //黄冈
                "#EA7E53", //黄石
                "#EEDD78", //荆门
                "#759AA0", //荆州
                "#1e9d95", //潜江
                "#7289AB", //神农架
                "#E69D87", //十堰
                "#47c0d4", //随州
                "#d54873", //天门
                "#ff1c12", //武汉
                "#ff8603", //仙桃
                "#4B8E6F", //咸宁
                "#ff6131", //襄阳
                "#ffde1d", //孝感
                "#386F38", //宜昌
                "#388589",
                "#385177",
                "#50964A",
                "#C16B0D",
                "#FF190F",
                "#45BFD3",
                "#FF5F2F",
                "#50F3A8",
                "#FF4800",
                "#FFDE1A",
                "#41D541",
                "#32E7EF",
                "#3B7CDE",
                "#58FD4A",
                "#FF8500"
        ];

        const renderinit = function(data, seq){
            // Linear Scale: Data Space -> Screen Space; 
            xScale = d3.scaleLinear()
            .domain(d3.extent(data, xValue))
            .range([0, innerWidth])
            .nice();

            // Introducing y-Scale; 
            yScale = d3.scaleLinear()
            .domain(d3.extent(data, yValue).reverse()) // "extent" is equivalent to [d3.min(data, xValue), d3.max(data, xValue)]; 
            .range([0, innerHeight])
            .nice();

            // generate maxX and maxY; 
            maxX = xScale(d3.max(data, xValue));
            maxY = yScale(d3.max(data, yValue));

            // The reason of using group is that nothing is rendered outside svg, so margin of svg is always blank while margin of group is rendered inside svg; 
            const g = svg.append('g')
            .attr('transform', `translate(${margin.left}, ${margin.top})`)
            .attr('id', 'maingroup');

            // Adding axes; 
            const yAxis = d3.axisLeft(yScale)
            .tickSize(-innerWidth)
            // .tickFormat(d3.format('.2s'))
            .tickPadding(10); // .tickPadding is used to prevend intersection of ticks; 
            const xAxis = d3.axisBottom(xScale)
            //.tickFormat(d3.format('.2s'))
            .tickSize(-innerHeight)
            .tickPadding(10);

            let yAxisGroup = g.append('g').call(yAxis).attr('id', 'yaxis');
            yAxisGroup.append('text')
            .attr('transform', `rotate(-90)`)
            .attr('x', -innerHeight / 2)
            .attr('y', -80)
            .attr('fill', 'white')
            .text('')
            .attr('text-anchor', 'middle') // Make label at the middle of axis. 
            yAxisGroup.selectAll('.domain').remove(); // we can select multiple tags using comma to seperate them and we can use space to signify nesting; 
            
            let xAxisGroup = g.append('g').call(xAxis)
            .attr('id', 'xaxis')
            .attr('transform', `translate(${0}, ${innerHeight})`);
            xAxisGroup.append('text')
            .attr('y', 60)
            .attr('x', innerWidth / 2)
            .attr('fill', 'white')
            .text('');
            xAxisGroup.selectAll('.domain').remove();
            
            // document.getElementById('yaxis').getElementsByClassName('tick')[1].getElementsByTagName('text')[0].textContent = 'shaokui'
            // let leftTicks = document.getElementById('yaxis').getElementsByClassName('tick');
            // let tid = 0;
            // let myticks = [];
            // for(tid = 0; tid < leftTicks.length; tid++){
            //     console.log(Math.pow(Math.E, +(leftTicks[tid].textContent)))
            //     myticks.push(parseFloat(Math.ceil(Math.pow(Math.E, +(leftTicks[tid].textContent)) - 1).toPrecision(1)));
            // }
            // for(tid = 0; tid < myticks.length; tid++){
            //     leftTicks[tid].getElementsByTagName('text')[0].textContent = myticks[tid];
            // }

            myticks = [0, 2, 10, 20, 50, 150, 400, 1100, 3000, 8100, 22000, 60000]
            for(let tid = 0; tid < myticks.length; tid++){
                document.getElementById('xaxis').getElementsByClassName('tick')[tid].getElementsByTagName('text')[0].textContent = myticks[tid];
            }

            myticks = [0, 0.2, 1, 2, 5, 15, 40, 110, 300, 800].reverse();
            for(let tid = 0; tid < myticks.length; tid++){
                document.getElementById('yaxis').getElementsByClassName('tick')[tid].getElementsByTagName('text')[0].textContent = myticks[tid];
            }

            // let bottomTicks = document.getElementById('xaxis').getElementsByClassName('tick');
            // myticks = [];
            // for(tid = 0; tid < bottomTicks.length; tid++){
            //     myticks.push(Math.ceil(Math.pow(Math.E, +(bottomTicks[tid].textContent))) - 1);
            // }
            // for(tid = 0; tid < myticks.length; tid++){
            //     bottomTicks[tid].getElementsByTagName('text')[0].textContent = myticks[tid];
            // }

            var legend_color = [
                "#ff1c12", //武汉
                "#EA7E53", //黄石
                "#E69D87", //十堰
                "#759AA0", //荆州
                "#386F38", //宜昌
                "#ff6131", //襄阳
                "#c25ec3", //鄂州
                "#EEDD78", //荆门
                "#ffde1d", //孝感
                "#52f3a9", //黄冈
                "#4B8E6F", //咸宁
                "#73A373", //恩施州
                "#47c0d4", //随州
                "#ff8603", //仙桃
                "#d54873", //天门
                "#1e9d95", //潜江
                "#7289AB", //神农架
            ];
            
            // var legend_name = ["武汉市",
            //     "黄石市",
            //     "十堰市",
            //     "荆州市",
            //     "宜昌市",
            //     "襄阳市",
            //     "鄂州市",
            //     "荆门市",
            //     "孝感市",
            //     "黄冈市",
            //     "咸宁市",
            //     "恩施州",
            //     "随州市",
            //     "仙桃市",
            //     "天门市",
            //     "潜江市",
            //     "神农架",
            // ];

            var legend_name1 = ["Wuhan",
                "Huangshi",
                "Shiyan",
                "Jingzhou",
                "Yichang",
                "Xiangyang",
                "Ezhou",
                "Jingmen",
                "Xiaogan",
                "Huanggang",
                "Xianning",
                "Enshi",
                "Suizhou",
                "Xiantao",
                "Tianmen",
                "Qianjiang",
                "Shennongjia",
            ];

            // draw legend
            var legend = d3.select('#maingroup').selectAll(".legend")
            .data(seq, d => d['地区'])
            .enter().append("g")
            .attr("class", "legend")
            .attr("transform", function(d, i) { return "translate(" + (innerWidth + 10) + "," + (i * 25 + 290) + ")"; });
			
            // draw legend colored rectangles
            legend.append("rect")
            .data(seq) 
            .attr("x", 0)
            .attr("y", 0)
            .attr("width", 30)
            .attr("height", 20)
            .style("fill", function (d,i) { return legend_color[i];});
			
            // draw legend text
            legend.append("text")
            .data(seq) 
            .attr('class', 'legend_text')
            .attr("x", 40)
            .attr("y", 9)
            .attr("dy", ".5em")
            .attr("fill", 'white')
            .style("text-anchor", "start")
            .text(function (d,i) {return legend_name1[i];});

        };
        
        const renderupdate = function(seq){
            const g = d3.select('#maingroup');
            time = seq[0]['日期'];
            g.selectAll('.date_text').remove();
            g.append("text")
            .data(['seq']) 
            .attr('class', 'date_text')
            .attr("x", innerWidth - 30)
            .attr("y", innerHeight / 10 - 20)
            .attr("dy", ".5em")
            .style("text-anchor", "end")
            .attr("fill", "#a6a5a5")
            .text(time);

            circleupdates = g.selectAll('circle').data(seq, d => d['地区']);
            circleenter = circleupdates.enter().append('circle')
            .attr('cy', (datum) => { return yScale(yValue(datum)) })
            .attr('cx', (datum) => { return xScale(xValue(datum)) }) // use xSacle to re-scale data space (domain) and return the rescaled population; 
            .attr('r', datum => rValue(datum))
            .attr('stroke-width', 2)
            .attr('stroke', '#cccccc')
            .attr('fill', function(d,i) {return color[i]}) // #3fd4c5
            .attr('opacity', .85);
            circleupdates.merge(circleenter).transition().ease(d3.easeLinear).duration(aduration)
            .attr('cy', (datum) => { return yScale(yValue(datum)) })
            .attr('cx', (datum) => { return xScale(xValue(datum)) }) // use xSacle to re-scale data space (domain) and return the rescaled population; 
            .attr('r', datum => rValue(datum));
            console.log(seq);

            textupdates = g.selectAll('.province_text').data(seq);
            textenter = textupdates.enter().append('text')
            .attr("class", "province_text")
            .attr("x", (datum) => { return xScale(xValue(datum)) + city_offset_x[datum[keyHint]]; })
            .attr("y", (datum) => { return yScale(yValue(datum)) - 15 + city_offset_y[datum[keyHint]]; })
            .attr("dy", ".1em")
            .style("text-anchor", "middle")
            .attr("fill", "#333333")
            //.attr('opacity', 0)
            .text(function (d,i) { 
                console.log(d);
                return name_map[d[keyHint]];
            });

            textupdates.merge(textenter).transition().ease(d3.easeLinear).duration(aduration)
            .attr('x', (datum) => { return xScale(xValue(datum)) + city_offset_x[datum[keyHint]]; })
            .attr('y', (datum) => { return yScale(yValue(datum)) - 23 + city_offset_y[datum[keyHint]] + rValue(datum); });
        };

        d3.csv('./static/data/hubeipop.csv').then(data => {
            data.forEach(datum => {
                datum['人口（万人）'] = +(datum['人口（万人）']);
            })
            metapop = data;
        });

        d3.csv('./static/data/hubeinxt.csv').then(function(data){
            
            data = data.filter(datum => {return datum['地区'] !== '总计'});
            data.forEach(datum => {
                // pre-process the data; 
                datum['确诊人数'] = +(datum['确诊人数']);
                datum['治愈人数'] = +(datum['治愈人数']);
                datum['死亡人数'] = +(datum['死亡人数']);
                datum['新增确诊'] = +(datum['新增确诊']);
                if(isNaN(datum['扩散曲线'])){
                    datum['扩散曲线'] = 0.0;
                }else{
                    datum['扩散曲线'] = +(datum['扩散曲线']);
                }
                datum['感染率'] = datum['确诊人数'] / (metapop.find(x => x['地区'] === datum['地区'])['人口（万人）']);
            });

            // remove duplicated items; 
            alldates = Array.from(new Set(data.map( datum => datum['日期'])));

            // make sure dates are listed according to real time order; 
            alldates = alldates.sort(function(a,b){
                // turn your strings into dates, and then subtract them
                // to get a value that is either negative, positive, or zero.
                return new Date(b.date) - new Date(a.date);
            });
            dates = alldates;

            // re-arrange the data sequentially; 
            sequential = []; 
            alldates.forEach(datum => {
                sequential.push([]);
            });
            data.forEach(datum => {
                sequential[alldates.indexOf(datum['日期'])].push(datum);
            });
            
            // smooth '扩散曲线' & calculate 'newinfec' (新增确诊数); 
            let t = 0;
            for(; t < sequential.length; t++){
                sequential[t].forEach(datum => {
                    if(t == 0){
                        datum['diffuse_smooth'] = datum['扩散曲线'];
                    }else if(t == 1){
                        datum['diffuse_smooth'] = (
                            datum['扩散曲线'] + 
                            sequential[t-1].find(x => x['地区'] === datum['地区'])['扩散曲线']
                        ) / 2.0;
                    }else{
                        datum['diffuse_smooth'] = (
                            datum['扩散曲线'] + 
                            sequential[t-1].find(x => x['地区'] === datum['地区'])['扩散曲线'] + 
                            sequential[t-2].find(x => x['地区'] === datum['地区'])['扩散曲线']
                        ) / 3.0;
                    }

                    if(t == 0){
                        datum['newinfec'] = 0;
                    }else{
                        datum['newinfec'] = datum['确诊人数'] - sequential[t-1].find(x => x['地区'] === datum['地区'])['确诊人数']
                        if(datum['newinfec'] < 0){
                            console.log(datum)
                        }
                    }
                })
            }

            // initialize the chart; 
            renderinit(data, sequential[0]);

            // set the animation interval; 
            let c = 0; 
            intervalId = setInterval(function(){
                if(c >= alldates.length){
                    console.log('time to close this animation');
                    clearInterval(intervalId); 
                }else{
                    // c = alldates.length - 1;
                    renderupdate(sequential[c]);
                    c = c + 1;
                }
            }, aduration); 
        });
    </script>
  </body>
</html>